#include <stdio.h>
#include <winsock2.h>

#include "YXConstant.h"
#include "YXLog.h"
#include "YXNet.h"

typedef struct {
    struct pollfd *events;
} ApiState;

int yxApiCreate(EventLoop *event_loop) {
    ApiState *state = malloc(sizeof(ApiState));
    if (state == NULL)
        return YX_ERR;

    // 初始化事件槽空间
    state->events = malloc(sizeof(struct pollfd) * event_loop->set_size);
    for (int i = 0; i < event_loop->set_size; i++) {
        state->events[i].fd = -1;
        state->events[i].events = 0;
        state->events[i].revents = 0;
    }
    if (state->events == NULL) {
        logErrno();
        exit(EXIT_FAILURE);
    }

    event_loop->api_data = state;

    return YX_OK;
}

void yxApiDelete(EventLoop *event_loop) {
    ApiState *state = event_loop->api_data;

    free(state->events);
    free(state);
}

int yxApiAddEvent(EventLoop *event_loop, int fd, int mask) {
    ApiState      *state = event_loop->api_data;
    struct pollfd *event = &state->events[fd];

    mask |= event_loop->events[fd].mask;

    if (mask & YX_NET_READABLE)
        event->events |= POLLIN;
    if (mask & YX_NET_WRITABLE)
        event->events |= POLLOUT;
    event->fd = fd;

    return YX_OK;
}

void yxApiDelEvent(EventLoop *event_loop, int fd, int delmask) {
    ApiState *state = event_loop->api_data;
    struct pollfd *event = &state->events[fd];

    if (delmask & YX_NET_READABLE) {
        event->events &= ~POLLIN;
    }
    if (delmask & YX_NET_WRITABLE) {
        event->events &= ~POLLOUT;
    }
}

int yxApiPoll(EventLoop *event_loop, long long timeout) {
    ApiState *state = event_loop->api_data;

    int event_nums = WSAPoll(state->events, event_loop->set_size, timeout);
    if (event_nums == -1) {
        return 0;
    }

    for (int i = 0, j = 0 ; i < event_loop->set_size, j < event_nums ; i++) {
        int            mask  = 0;
        struct pollfd *event = state->events + i;
        if (event->revents & POLLIN)
            mask |= YX_NET_READABLE;
        if (event->revents & POLLOUT)
            mask |= YX_NET_WRITABLE;
        if (event->revents & POLLERR)
            mask |= YX_NET_WRITABLE;
        if (event->revents & POLLHUP)
            mask |= YX_NET_WRITABLE;

        if (mask != 0) {
            event_loop->fired_events[j].fd   = event->fd;
            event_loop->fired_events[j].mask = mask;
            j++;
        }
    }
    return event_nums;
}